/*
******************************************************************************************************* 
**  Copyright (C) 2019, 苏州检易生物科技有限公司 
**  All rights reserved. 
** 
**  FileName:       	tcp_transfer.c
**  Description:	与上位机连接的传输层协议
**  Author:        	 
**  Version				v0.1
**  Date:           	20221017
**	Function List： 
**  History:         
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                              	调试开关
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/
#include "tcp_transfer.h"
#include "crc16.h"



/*
*********************************************************************************************************
*                                              	宏定义
*********************************************************************************************************
*/
#define ETH_RECV_MEM_LENGTH 1500
/*
*********************************************************************************************************
*                                              	结构体定义
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                              	函数原型声明
*********************************************************************************************************
*/
static void transfer_timer_callback(void* arg);
static void transfer_output(protocol_cmd_t cmd,uint32_t win,void* buff,uint16_t size);
static uint16_t transfer_crc(uint8_t* buff);
/*
*********************************************************************************************************
*                                              	全局变量定义
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                              	模块静态变量定义
*********************************************************************************************************
*/
static transfer_send_node_t* p_send_head = NULL;
static tcp_input_callback tcp_protocol_input;
/*
*********************************************************************************************************
*                                              	函数定义
*********************************************************************************************************
*/

transfer_err_t tcp_transfer_init(tcp_input_callback pfn_callback)
{
	tcp_protocol_input = pfn_callback;
	return TRANSFER_ERR_NONE;
}
void transfer_input(uint8_t* buff,uint16_t size)
{
	/*考虑存在上位机命令帧被拆分的情况*/
	static uint8_t recv_buff[ETH_RECV_MEM_LENGTH];
	static uint16_t recv_size = 0;
//	rt_base_t it = rt_hw_interrupt_disable();
	transfer_head_t *p_head = (transfer_head_t*)recv_buff;
	transfer_send_node_t* p_node;
	uint16_t crc16 = 0;
	if(buff != NULL)
	{
		/*是全帧或者头部帧*/
		if(recv_size == 0 && buff[0] == TRANSFER_HEAD)
		{
			memcpy(recv_buff,buff,size);
			recv_size = size;
		}
		/*非头部的拆分帧*/
		else if(recv_size != 0)
		{
			if(recv_size + size > ETH_RECV_MEM_LENGTH)
			{
//				Critical_Log("Recv a illegal tcp frame!\r\n");
				recv_size = 0;
				return;
			}
			memcpy(recv_buff + recv_size,buff,size);
			recv_size += size;
		}
		else
		{
//			Trace_Log("Recv a illegal tcp frame!\r\n");
			recv_size = 0;
			return;
		}
		
		p_head = (transfer_head_t*)recv_buff;
		/*如果累计收到一个合理的帧*/
		if(recv_buff[0] == TRANSFER_HEAD &&
//			p_head->length == recv_size &&
			*(recv_buff + p_head->length - 1) == TRANSFER_TAIL)
		{
		}
		else
		{
			return;
		}
	}
	if(p_head == NULL || recv_size == 0)
		return;
	while(recv_size != 0)
	{
		crc16 = transfer_crc(recv_buff);
		if(crc16 != *((uint16_t*)(recv_buff + p_head->length - sizeof(transfer_tail_t))) )
		{
		//Trace_Log("TCP msg id %d crc check failed!",p_head->win);
			return;
		}
		if(tcp_protocol_input != NULL)
			tcp_protocol_input(p_head->cmd,recv_buff + sizeof(transfer_head_t),TRANSFER_SEND_DATA_LEN(p_head->length));
		if(p_head->length < recv_size)
		{
			recv_size = recv_size - p_head->length;
			memcpy(recv_buff,recv_buff + p_head->length,recv_size);
		}
		else{
			memset(recv_buff,0,recv_size);
			recv_size = 0;
		}
	}
}

uint16_t tcp_get_send(uint8_t* buff)
{
	if(p_send_head == NULL)
		return 0;
	portDISABLE_INTERRUPTS();
	transfer_send_node_t* p_send = p_send_head;
	p_send_head = p_send_head->next;
	uint16_t size = p_send->size;
	memcpy(buff,p_send->buff,p_send->size);
	free(p_send);
	portENABLE_INTERRUPTS();
	return size;
}
transfer_err_t tcp_transfer_push(protocol_cmd_t cmd,void* buff,uint16_t size)
{
	if(size > TRANSFER_SEND_SIZE_MAX)
	{ 
		while(1){}
	}
	transfer_send_node_t* p_new = malloc(sizeof(transfer_send_node_t));
	if(p_new == NULL)
		return 0;
	portDISABLE_INTERRUPTS();
	p_new->size = sizeof(transfer_head_t) + sizeof(transfer_tail_t) + size;
	p_new->next = NULL;
	
	transfer_head_t* p_head = (transfer_head_t*)p_new->buff;
	p_head->head = TRANSFER_HEAD;
	p_head->cmd = cmd;
	p_head->length = p_new->size;
	if(size != 0)
		memcpy(p_new->buff + sizeof(transfer_head_t),buff,size);
	transfer_tail_t* p_tail = (transfer_tail_t*)(p_new->buff + sizeof(transfer_head_t) + size);
	p_tail->tail = TRANSFER_TAIL;
	p_tail->modbus_crc = transfer_crc(p_new->buff);
	
	transfer_send_node_t* p_next = p_send_head;
	if(p_send_head == NULL)
		p_send_head = p_new;
	else
	{
		while(p_next->next != NULL)
		{
			p_next = p_next->next;
		}
		p_next->next = p_new;
	}
	portENABLE_INTERRUPTS();
	return 0;
}

static uint16_t transfer_crc(uint8_t* buff)
{
	if(NULL == buff)
		return 0;
	transfer_head_t *p_head = (transfer_head_t*)buff;
	return ModBusCRC((uint8_t*)&p_head->win,p_head->length - 4);
}